package handlers

import (
    "net/http"
    "path/filepath"
    "strconv"

    "github.com/gin-gonic/gin"

    "github.com/samaa/photosalesplus/backend/internal/config"
    "github.com/samaa/photosalesplus/backend/internal/repositories"
    "github.com/samaa/photosalesplus/backend/internal/services"
    "github.com/samaa/photosalesplus/backend/internal/storage"
)

type AssetHandler struct {
    cfg           *config.Config
    authService   services.AuthService
    userRepo      repositories.UserRepository
    mediaRepo     repositories.MediaAssetRepository
    productRepo   repositories.ProductRepository
    orderRepo     repositories.OrderRepository
}

func NewAssetHandler(
    cfg *config.Config,
    auth services.AuthService,
    userRepo repositories.UserRepository,
    mediaRepo repositories.MediaAssetRepository,
    productRepo repositories.ProductRepository,
    orderRepo repositories.OrderRepository,
) *AssetHandler {
    return &AssetHandler{cfg: cfg, authService: auth, userRepo: userRepo, mediaRepo: mediaRepo, productRepo: productRepo, orderRepo: orderRepo}
}

// GetOriginal streams the original image if the requester is authorized.
// Auth: Accepts Bearer token in header, or `token` query parameter.
func (h *AssetHandler) GetOriginal(c *gin.Context) {
    idVal, err := strconv.Atoi(c.Param("id"))
    if err != nil || idVal <= 0 {
        c.JSON(http.StatusBadRequest, APIResponse{Error: "invalid asset id"})
        return
    }

    // Validate token (header or query)
    token := ""
    authHeader := c.GetHeader("Authorization")
    if authHeader != "" {
        token = authHeader
        if len(token) > 7 && (token[:7] == "Bearer " || token[:7] == "bearer ") {
            token = token[7:]
        }
    }
    if token == "" {
        token = c.Query("token")
    }
    if token == "" {
        c.JSON(http.StatusUnauthorized, APIResponse{Error: "未授权"})
        return
    }

    userID, ok := h.authService.Validate(c.Request.Context(), token)
    if !ok {
        c.JSON(http.StatusUnauthorized, APIResponse{Error: "凭证已失效"})
        return
    }

    // Fetch user to get username
    user, err := h.userRepo.FindByID(c.Request.Context(), userID)
    if err != nil || user == nil {
        c.JSON(http.StatusUnauthorized, APIResponse{Error: "用户不存在"})
        return
    }

    // Map asset -> product
    productID, err := h.productRepo.FindProductIDByAssetID(c.Request.Context(), uint(idVal))
    if err != nil || productID == 0 {
        c.JSON(http.StatusNotFound, APIResponse{Error: "未找到资源对应的商品"})
        return
    }

    // Check order entitlement (any non-canceled order)
    allowed, err := h.orderRepo.ExistsCustomerOrderForProduct(c.Request.Context(), user.Username, productID)
    if err != nil {
        c.JSON(http.StatusInternalServerError, APIResponse{Error: "校验订单失败"})
        return
    }
    if !allowed {
        c.JSON(http.StatusForbidden, APIResponse{Error: "未购买，无法下载原图"})
        return
    }

    // Load asset for original path
    asset, err := h.mediaRepo.GetByID(c.Request.Context(), uint(idVal))
    if err != nil || asset == nil || asset.OriginalPath == "" {
        c.JSON(http.StatusNotFound, APIResponse{Error: "原图不存在"})
        return
    }

    // Build absolute path and serve file inline
    abs := storage.AbsolutePath(h.cfg, asset.OriginalPath)
    c.Header("Content-Type", asset.MimeType)
    c.Header("Content-Disposition", "inline; filename="+filepath.Base(asset.OriginalPath))
    c.File(abs)
}

